package com.yellowpage.white.dao;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.persistence.Entity;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;

import com.yellowpage.white.dao.HibernateMapping;
import com.yellowpage.white.dao.WhiteAnnotationSessionFactoryBean;
import com.yellowpage.white.util.FileUtil;

public class WhiteAnnotationSessionFactoryBean extends AnnotationSessionFactoryBean {
	
	private static Log logger = LogFactory.getLog(WhiteAnnotationSessionFactoryBean.class);
	
	protected void postProcessMappings(AnnotationConfiguration cfg) throws HibernateException {
		if (this.annotatedPkgs != null) {
			for (int i = 0; i < this.annotatedPkgs.length; i ++) {
				try {
					addPackageMapping(this.annotatedPkgs[i], cfg);
				} catch (ClassNotFoundException e) {
					logger.error("can not find package" + this.annotatedPkgs[i], e);
				}
			}
		}
	}
	
	protected void scanPackages(Configuration config){
		
	}
	
	
	
	/**
	 * 加载每一个目录下的所有hbm文件
	 * @param pkg
	 * @param cfg
	 * @throws ClassNotFoundException 
	 */
	private void addPackageMapping(String pkg, AnnotationConfiguration cfg) throws ClassNotFoundException {
		List<Class> list = (this.loadBySearch)?getPackageMapping(pkg):getPackageMappingByPackageInfo(pkg);
		Iterator<Class> i = list.iterator();
		while (i.hasNext()) {
			cfg.addAnnotatedClass(i.next());
		}
		
	}
	
	
	//属性设定
	private String[] annotatedPkgs = null;
	public void setAnnotatedPkgs(String[] annotatedPkgs) {
		this.annotatedPkgs = annotatedPkgs;
	}
	
	private boolean loadBySearch = true;
	public void setLoadBySearch(boolean loadBySearch) {
		this.loadBySearch = loadBySearch;
	}
	
	/**
	 * 根据package搜索下面的类，如果有entity的标志表示需要加载
	 * @param name
	 * @return
	 * @throws ClassNotFoundException
	 */
	public static List<Class> getPackageMapping(String name) throws ClassNotFoundException {
		if (name.indexOf(".") != -1) name = name.replace('.', '/');
		
		List<String> l = null;
		//搜索类
		try {
			logger.debug("find hibernate domain package:" + name);
			String pattern = ".*\\.class";
			l = FileUtil.searchFileFromClassPath(name, pattern);
			logger.debug("find heibernat domain package result:" + l);
		} catch (Exception e) {
			logger.error("search hibernate domain package package error:" + name, e);
			l = new ArrayList<String>();
		}
		
		//加载class
		Iterator<String> i = l.iterator();
		List<Class> clazz = new ArrayList<Class>();
		while (i.hasNext()) {
			String clsName = i.next();
			//logger.debug("deal hibernate domain name:" + clsName);
			clsName = clsName.substring(0, clsName.length() - 6);
			clsName = clsName.replace('/', '.');
			//logger.debug("deal hibernate domain name result:" + clsName);
			
			Class<?> c = Class.forName(clsName, true, Thread.currentThread().getContextClassLoader());
			Entity entity = c.getAnnotation(Entity.class);
			
			//如果被注释成hibernate bean
			if (entity != null) {
				clazz.add(c);
				logger.debug("hibrenate domain class " + clsName + "loaded");
			}
		}
		return clazz;
	}
	
	/**
	 * 根据package中配置mapping信息进行映射
	 * @param name  包名
	 * @return
	 * @throws ClassNotFoundException 
	 * @throws ClassNotFoundException
	 */
	public static List<Class> getPackageMappingByPackageInfo(String name) throws ClassNotFoundException {
		if (name.indexOf("/") != -1) name = name.replace('/', '.');
		
		Package p = Thread.currentThread().getContextClassLoader().loadClass(name + ".package-info").getPackage();
		List<Class> list = new ArrayList<Class>();
		if (p.isAnnotationPresent(HibernateMapping.class)) {
			HibernateMapping h = p.getAnnotation(HibernateMapping.class);
			Class[] c = h.resources();
			
			for (int i = 0; i < c.length; i ++) {
				list.add(c[i]);
			}
		}
		return list;
	}
}
